#pragma once 
#include <iostream>
#include <queue>
#include <pthread.h>
#define MAXCAPACITY 5

template<class T>
class Blockqueue{

public:
    Blockqueue(const int maxcap = MAXCAPACITY):_maxcap(maxcap){
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_c_cond,nullptr);
        pthread_cond_init(&_p_cond,nullptr);

    }

    void push(const T& date){ //输入型参数
        //对临界资源需要加锁保护
        pthread_mutex_lock(&_mutex);
        while(isfull())    pthread_cond_wait(&_p_cond,&_mutex); //判断如果数据满了就进入生产者的条件变量中等待,要用whie循环做判断
        //因为如果是只剩一个空位，而调用了boardcast唤醒时，都会解开锁，此时会导致伪唤醒问题

        _q.push(date); 
        
        //此时就可以通知消费者，当然可以添加lowwater触发条件
        pthread_cond_signal(&_c_cond);
    
        pthread_mutex_unlock(&_mutex);

    }

    void pop(T* data){  //输出型参数
        pthread_mutex_lock(&_mutex);
        
        while(isempty())    pthread_cond_wait(&_c_cond,&_mutex);

        *data = _q.front();
        _q.pop();

        pthread_cond_signal(&_p_cond);

        pthread_mutex_unlock(&_mutex);

    }

    ~Blockqueue(){
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

private:
    bool isempty(){
        return  _q.empty();
    }
    bool isfull(){
        return _q.size() == _maxcap;
    }

private:
    std::queue<T> _q;
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
    int _maxcap;
};